<!-- This Source Code Form is subject to the terms of the Mozilla Public
   - License, v. 2.0. If a copy of the MPL was not distributed with this
   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->

<script type="text/javascript;version=1.7">
/* [pseudo_color, pseudo_background, bubble_borders] */
const elements_lightness = [[75, 94, 80], [75, 94, 80], [70, 93, 75], [65, 92, 70], [55, 90, 65], [48, 90, 60], [44, 86, 50], [44, 88, 60], [45, 88, 70], [45, 90, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [45, 92, 70], [60, 92, 70], [70, 93, 75], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80], [75, 94, 80]];

const bubble_background = "hsl(#, 100%, 97%)";
const bubble_borders = "hsl(#, 100%, #%)";
const pseudo_color = "hsl(#, 100%, #%)";
const pseudo_background = "hsl(#, 100%, #%)";

function setColors(target)
{
  var senderColor = target.getAttribute("senderColor");

  if (!senderColor)
    return;

  var regexp = /color:\s*hsl\(\s*(\d{1,3})\s*,\s*\d{1,3}\%\s*,\s*\d{1,3}\%\s*\)/;
  var parsed = regexp.exec(senderColor);

  if (!parsed)
    return;

  var senderHue = ((Math.round(parsed[1]/10))*10)%360;
  var lightness = elements_lightness[senderHue/10];

  target.style.backgroundColor = bubble_background.replace("#", senderHue);
  target.style.borderColor = bubble_borders.replace("#", senderHue)
                                           .replace("#", lightness[2]);

  var span_pseudo = target.getElementsByClassName("pseudo")[0].firstChild;
  span_pseudo.style.color = pseudo_color.replace("#", senderHue)
                                        .replace("#", lightness[0]);
  span_pseudo.style.backgroundColor = pseudo_background.replace("#", senderHue)
                                                       .replace("#", lightness[1]);

  var div_indicator = target.getElementsByClassName("indicator")[0];
  var imageURL = document.defaultView.getComputedStyle(div_indicator, null).backgroundImage;

  var regexp2 = /(indicator_)(\d{1,3})([_.])/;
  div_indicator.style.backgroundImage = imageURL.replace(regexp2, "$1" + senderHue + "$3");

  // Will be applied to action messages as text color.
  div_indicator.style.borderColor = pseudo_color.replace("#", senderHue).replace("#", lightness[0] - 15);
}


function groupEvents(parent)
{
  var P_list = parent.getElementsByClassName("event");

  if (P_list.length < 4)
    return;

  var HR_list = parent.getElementsByTagName("hr");

  if (P_list[1].hasAttribute("style"))
  {
    var prevStyle = P_list[1].style.display;
    var nbEvents = P_list.length;

    P_list[nbEvents-2].style.display = prevStyle;
    HR_list[nbEvents-3].style.display = prevStyle;
  }
  else
  {
    var nbEvents = P_list.length;

    for (var i=1; i < (nbEvents-2); i++)
    {
      P_list[i].style.display = "none";
      HR_list[i].style.display = "none";
    }
    P_list[i].style.display = "none";

    var p = document.createElement("p");
    p.addEventListener("click", toggle_groupEvents);
    p.setAttribute("class", "button hide");
    parent.insertBefore(p, P_list[1]);
  }
}


function toggle_groupEvents(aEvent)
{
  if (aEvent.detail > 1)
    return;

  var target = aEvent.target;
  var P_list = target.parentNode.getElementsByClassName("event");
  var HR_list = target.parentNode.getElementsByTagName("hr");
  var nbEvents = P_list.length;

  if (target.className == "button hide") {
    for (var i=1; i < (nbEvents-2); i++) {
      P_list[i].style.display = "block";
      HR_list[i].style.display = "block";
    }
    P_list[i].style.display = "block";

    target.className = "button show";
  }
  else {
    for (var i=1; i < (nbEvents-2); i++) {
      P_list[i].style.display = "none";
      HR_list[i].style.display = "none";
    }
    P_list[i].style.display = "none";

    target.className = "button hide";
  }
}

function prettyPrintTime(aValue, aNoSeconds) {
  if (aValue < 60 && aNoSeconds)
    return "";

  if (aNoSeconds)
    aValue -= aValue % 60;

  let valuesAndUnits = window.convertTimeUnits(aValue);
  if (!valuesAndUnits[2])
    valuesAndUnits.splice(2, 2);
  return valuesAndUnits.join(" ");
}

// The "shadow" constant is the minimum acceptable margin-bottom for a bubble
// with a shadow, and the minimum spacing between the bubbles of two messages
// arriving in the same second. It should match the value of margin-bottom and
// box-shadow-bottom for the "bubble" class.
const shadow = 3;
const coef = 3;
const timebeforetextdisplay = 5 * 60;
const kRulerMarginTop = 11;

function computeSpace(aInterval)
  Math.round(coef * Math.log(aInterval + 1))

function refreshIntervals()
{
  var pixels = 1;
  var previousTime = 0;
  while (true) {
    var time = Math.exp((pixels - 0.49999) / coef) - 1;
    if (time >= timebeforetextdisplay)
      break;

    time = Math.round(time * 1000);
    var result = time - previousTime;
    previousTime = time;
    yield result;
    ++pixels;
  }
  while (true)
    yield 60 * 1000;
}

var lastMessageTimeout;
function handleLastMessage(aGenerator)
{
  var interval = Math.round(Date.now() / 1000) - lastInsertTime;
  var p = document.getElementById("lastMessage");
  var margin = computeSpace(interval);
  var text = "";
  if (interval >= timebeforetextdisplay) {
    p.style.lineHeight = (margin + shadow) + "px";
    p.setAttribute("class", "interval");
    text = prettyPrintTime(interval, true);
    margin = 0;
  }
  p.textContent = text;
  p.style.marginTop = (margin - shadow) + "px";
  var body = document.getElementsByTagName("body")[0];
  if (body.scrollHeight <= body.scrollTop + body.clientHeight + p.clientHeight + 10)
    scrollToElement(p);
  lastMessageTimeout =
    setTimeout(handleLastMessage, aGenerator.next(), aGenerator);
}

var lastInsertTime = 0;
function updateLastInsertTime()
{
  let insertTime = document.getElementById("insert").getAttribute("time");
  if (insertTime > lastInsertTime)
    lastInsertTime = insertTime;
}
function checkNewText(aEvent)
{
  var target = aEvent.originalTarget;
  if (!(target instanceof HTMLElement))
    return;

  if (target.tagName == "DIV" && target.className.substring(0, 6) == "bubble") {
    setColors(target);
    let pElts = target.getElementsByTagName("p");
		for (var i = 0, pElt; pElt = pElts[i]; i++) {
	    if (pElt.className.substring(0, 6) == "action")
	      pElt.style.color = pElt.parentNode.style.borderColor;
		}
    var prev = target.previousSibling;
    var shouldSetUnreadRuler = prev && prev.id && prev.id == "unread-ruler";
    // We need an extra pixel of margin at the top to make the margins appear
    // to be of equal size, since the preceding bubble will have a shadow.
    var rulerMarginBottom = kRulerMarginTop - 1;

    var insertTime = document.getElementById("insert").getAttribute("time");
    if (lastInsertTime && insertTime >= lastInsertTime) {
      var interval = insertTime - lastInsertTime;
      var margin = computeSpace(interval);
      if (interval >= timebeforetextdisplay) {
        var p = document.createElement("p");
        p.style.lineHeight = (margin + shadow) + "px";
        p.style.marginTop = -shadow + "px";
        p.setAttribute("class", "interval");
        p.textContent = prettyPrintTime(interval);
		var pMessages = target.getElementsByClassName("message");
		var taille = pMessages.length;
		var pMessage = pMessages[length-1];
        pMessage.parentNode.insert(p);
        margin = 0;
      }
      target.style.marginTop = margin + "px";
      if (shouldSetUnreadRuler) {
        if (margin > rulerMarginBottom) {
          // Set the unread ruler margin so it is constant after margin collapse.
          // See https://developer.mozilla.org/en/CSS/margin_collapsing
          rulerMarginBottom -= margin;
        }
        if (interval >= timebeforetextdisplay) {
          // If a text display follows, use the minimum bubble margin after the
          // ruler, taking account of the absence of a shadow on the ruler.
          rulerMarginBottom = shadow - 1;
        }
      }
    }
    updateLastInsertTime();
    if (shouldSetUnreadRuler) {
      prev.style.marginBottom = rulerMarginBottom + "px";
      prev.style.marginTop = kRulerMarginTop + "px";
    }
  }
  else if (target.tagName == "P" && target.classList.contains("action")) {
    target.style.color = target.parentNode.style.borderColor;
  }
  else if (target.tagName == "DIV" && target.id == "insert") {
    updateLastInsertTime();
  }
  else if (target.tagName == "P" && target.className == "event") {
    groupEvents(target.parentNode);
    updateLastInsertTime();
  }
  if (lastInsertTime) {
    clearTimeout(lastMessageTimeout);
    lastMessageTimeout = setTimeout(handleLastMessage, 0, refreshIntervals());
  }
}

document.getElementById("ibcontent")
        .addEventListener("DOMNodeInserted", checkNewText, false);
</script>

<p id="lastMessage"/>
